package com.chuangyiruanke.util;


import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.DateTimeException;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Pattern;

import static java.util.Calendar.*;

/**
 * Created by KK on 2017/2/13.
 */
public class DateUtil {
    /**
     * 将时间戳转换为时间
     *
     * @param time 时间戳
     * @return
     */
    public static String stampToDate(long time) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date date = new Date(time);
        String res = simpleDateFormat.format(date);
        return res;
    }

    /*
     * 将时间转换为时间戳
     */
    public static long dateToStamp(String time) {
        try {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date = simpleDateFormat.parse(time);
            long res = date.getTime();
            return res;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return 0;
    }

    /**
     * 获取公历指定月份的天数
     *
     * @param year
     * @param month
     * @return
     */
    public static int getDaysOfMonth(int year, int month) {
        switch (month) {
            case 3:
            case 5:
            case 8:
            case 10:
                return 30;
            case 1:
                if (isLeapYear(year)) {
                    return 29;
                }
                return 28;
            default:
                return 31;
        }
    }

    /**
     * 获取公历指定年份的天数
     *
     * @param year 年份
     * @return 该年份总天数
     */
    public static int getDaysOfYear(int year) {
        if (isLeapYear(year)) {
            return 366;
        }
        return 365;
    }

    /**
     * 获取指定年份是否为闰年
     *
     * @param year 年份
     * @return 如果指定年份为闰年，返回 true；否则返回 false。
     */
    public static boolean isLeapYear(int year) {
        return ((year & 3) == 0 && year % 100 != 0) || (year % 400 == 0);
    }

    public static Timestamp add(int fieldType, int value) {
        return add(getCurrentTimestamp(), fieldType, value);
    }

    public static Timestamp add(Date date, int fieldType, int value) {
        Calendar current = new Calendar.Builder().setInstant(date).build();
        current.add(fieldType, value);
        return new Timestamp(current.getTimeInMillis());
    }

    public static Timestamp addYear(int years) {
        return addYear(getCurrentTime(), years);
    }

    public static Timestamp addMonth(int months) {
        return addMonth(getCurrentTime(), months);
    }

    public static Timestamp addDay(int days) {
        return addDay(getCurrentTime(), days);
    }

    public static Timestamp addHour(int hours) {
        return addHour(getCurrentTime(), hours);
    }

    public static Timestamp addMinute(int minutes) {
        return addMinute(getCurrentTime(), minutes);
    }

    public static Timestamp addSecond(int seconds) {
        return addSecond(getCurrentTime(), seconds);
    }

    public static Timestamp addMillisecond(int milliseconds) {
        return addMillisecond(getCurrentTime(), milliseconds);
    }

    public static Timestamp addYear(Date date, int years) {
        Calendar current = new Calendar.Builder().setInstant(date).build();
        current.add(Calendar.YEAR, years);
        return new Timestamp(current.getTimeInMillis());
    }

    public static Timestamp addMonth(Date date, int months) {
        Calendar current = new Calendar.Builder().setInstant(date).build();
        current.add(Calendar.MONTH, months);
        return new Timestamp(current.getTimeInMillis());
    }

    public static Timestamp addDay(Date date, int days) {
        Calendar current = new Calendar.Builder().setInstant(date).build();
        current.add(Calendar.DAY_OF_MONTH, days);
        return new Timestamp(current.getTimeInMillis());
    }

    public static Timestamp addHour(Date date, int hours) {
        Calendar current = new Calendar.Builder().setInstant(date).build();
        current.add(Calendar.HOUR_OF_DAY, hours);
        return new Timestamp(current.getTimeInMillis());
    }

    public static Timestamp addMinute(Date date, int minutes) {
        Calendar current = new Calendar.Builder().setInstant(date).build();
        current.add(Calendar.MINUTE, minutes);
        return new Timestamp(current.getTimeInMillis());
    }

    public static Timestamp addSecond(Date date, int seconds) {
        Calendar current = new Calendar.Builder().setInstant(date).build();
        current.add(Calendar.SECOND, seconds);
        return new Timestamp(current.getTimeInMillis());
    }

    public static Timestamp addMillisecond(Date date, int milliseconds) {
        Calendar current = new Calendar.Builder().setInstant(date).build();
        current.add(Calendar.MILLISECOND, milliseconds);
        return new Timestamp(current.getTimeInMillis());
    }

    public static long addYear(long date, int years) {
        Calendar current = new Calendar.Builder().setInstant(new Date(date)).build();
        current.add(Calendar.YEAR, years);
        return current.getTimeInMillis();
    }

    public static long addMonth(long date, int months) {
        Calendar current = new Calendar.Builder().setInstant(new Date(date)).build();
        current.add(Calendar.MONTH, months);
        return current.getTimeInMillis();
    }

    public static long addDay(long date, int days) {
        Calendar current = new Calendar.Builder().setInstant(new Date(date)).build();
        current.add(Calendar.DAY_OF_MONTH, days);
        return current.getTimeInMillis();
    }

    public static long addHour(long date, int hours) {
        Calendar current = new Calendar.Builder().setInstant(new Date(date)).build();
        current.add(Calendar.HOUR_OF_DAY, hours);
        return current.getTimeInMillis();
    }

    public static long addMinute(long date, int minutes) {
        Calendar current = new Calendar.Builder().setInstant(new Date(date)).build();
        current.add(Calendar.MINUTE, minutes);
        return current.getTimeInMillis();
    }

    public static long addSecond(long date, int seconds) {
        Calendar current = new Calendar.Builder().setInstant(new Date(date)).build();
        current.add(Calendar.SECOND, seconds);
        return current.getTimeInMillis();
    }

    public static long addMillisecond(long date, int milliseconds) {
        Calendar current = new Calendar.Builder().setInstant(new Date(date)).build();
        current.add(Calendar.MILLISECOND, milliseconds);
        return current.getTimeInMillis();
    }

    /**
     * 获取当前时间的 java.util.Date 表示。
     *
     * @return 获取当前时间
     */
    public static Timestamp getCurrentTime() {
        return new Timestamp(System.currentTimeMillis());
    }

    /**
     * 获取当前时间的 java.sql.Timestamp 表示。
     *
     * @return
     */
    public static java.sql.Timestamp getCurrentTimestamp() {
        return new java.sql.Timestamp(System.currentTimeMillis());
    }

    /**
     * 获取从 00:00 到由 HH:mm[:ss] 格式的字符串指定的时间经过的分钟数。
     *
     * @param time HH:mm[:ss]格式的时间文本
     * @code 例如：传入"01:00"，返回 60；传入 "06:30" 返回 390。
     * @return 经过的分钟数。
     * @throws DateTimeException 传入文本格式有误
     */
    public static int getTotalMinuteByTime(String time) throws DateTimeException {
        if (StringUtils.isNullOrEmpty(time)) {
            return 0;
        }
        if (!Pattern.matches("^([0-9]|1[0-9]|2[0-4])(:([0-5][0-9])){1,2}$", time)) {
            throw new DateTimeException(String.format("%s是无效的时间格式！", time));
        }
        String[] values = time.split(":");
        int hour = Integer.parseInt(values[0]);
        int minute = Integer.parseInt(values[1]);
        return hour * 60 + minute;
    }

    /**
     * 获取从当日零点开始到现在经过的分钟数。
     *
     * @return
     */
    public static int getTotalMinuteInDay() {
        return getTotalMinuteInDay(Calendar.getInstance().getTimeInMillis());
    }

    /**
     * 获取从指定时间的当日零点开始到指定时间经过的分钟数。
     *
     * @param time
     * @return
     */
    public static int getTotalMinuteInDay(Date time) {
        return getTotalMinuteInDay(time.getTime());
    }

    /**
     * 获取从指定时间戳的当日零点开始到指定时间经过的分钟数。
     *
     * @param time
     * @return
     */
    public static int getTotalMinuteInDay(long time) {
        long date = setTime(time, 0, 0, 0, 0);
        long value = time - date;
        return (int) (value / (1000 * 60));
    }

    /**
     * 使用年月日获取时间戳
     *
     * @param year  年份
     * @param month 月份 从0开始
     * @param day   日期
     * @return
     */
    public static Timestamp getDate(int year, int month, int day) {
        Calendar.Builder builder = new Calendar.Builder();
        builder.setDate(year, month, day);
        return new Timestamp(builder.build().getTimeInMillis());
    }

    public static Timestamp getDayEnd() {
        return setTime(getCurrentTime(), 23, 59, 59, 0);
    }

    public static Timestamp getDayStart() {
        return setTime(getCurrentTime(), 0, 0, 0, 0);
    }

    public static Timestamp getDayEnd(Date date) {
        return setTime(date, 23, 59, 59, 0);
    }

    public static Timestamp getDayStart(Date date) {
        return setTime(date, 0, 0, 0, 0);
    }

    public static Timestamp getTimeOfDayEnd(long date) {
        long time = setTime(date, 23, 59, 59, 0);
        return new Timestamp(time);
    }

    public static Timestamp getTimeOfDayStart(long date) {
        long time = setTime(date, 0, 0, 0, 0);
        return new Timestamp(time);
    }

    public static long getDayEnd(long date) {
        return setTime(date, 23, 59, 59, 0);
    }

    public static long getDayStart(long date) {
        return setTime(date, 0, 0, 0, 0);
    }

    public static Timestamp getDayOfEnd(Date date) {
        long time = setTime(date.getTime(), 23, 59, 59, 0);
        return new Timestamp(time);
    }

    public static Timestamp getDayOfStart(Date date) {
        long time = setTime(date.getTime(), 0, 0, 0, 0);
        return new Timestamp(time);
    }

    @Deprecated
    public static long getDayOfEnd(long date) {
        return setTime(date, 23, 59, 59, 0);
    }

    @Deprecated
    public static long getDayOfStart(long date) {
        return setTime(date, 0, 0, 0, 0);
    }

    /**
     * 设置日期的时间属性
     *
     * @param date        从1970/1/1起经过的毫秒数。
     * @param hour        设置 date 所表示的时间的小时部分。
     * @param minute      设置 date 所表示的时间的分钟部分。
     * @param second      设置 date 所表示的时间的秒部分。
     * @param millisecond 设置 date 所表示的时间的毫秒部分。
     * @return 设置 '时:分:秒.毫秒' 后的时间的毫秒数表示。
     */
    public static long setTime(long date, Integer hour, Integer minute, Integer second, Integer millisecond) {
        return setTimeInner(date, hour, minute, second, millisecond);
    }

    /**
     * 设置日期的时间属性
     *
     * @param date        从1970/1/1起经过的毫秒数。
     * @param hour        设置 date 所表示的时间的小时部分。
     * @param minute      设置 date 所表示的时间的分钟部分。
     * @param second      设置 date 所表示的时间的秒部分。
     * @param millisecond 设置 date 所表示的时间的毫秒部分。
     * @return 设置 '时:分:秒.毫秒' 后的时间的毫秒数表示。
     */
    public static Timestamp setTime(Date date, Integer hour, Integer minute, Integer second, Integer millisecond) {
        long time = setTimeInner(date.getTime(), hour, minute, second, millisecond);
        return new Timestamp(time);
    }

    private static long setTimeInner(long date, Integer hour, Integer minute, Integer second, Integer millisecond) {
        Calendar.Builder builder = new Calendar.Builder();
        builder.setInstant(date);
        Calendar val = builder.build();
        if (hour != null) {
            val.set(Calendar.HOUR_OF_DAY, hour);
        }
        if (minute != null) {
            val.set(Calendar.MINUTE, minute);
        }
        if (second != null) {
            val.set(Calendar.SECOND, second);
        }
        if (millisecond != null) {
            val.set(MILLISECOND, millisecond);
        }
        return val.getTimeInMillis();
    }
}
